#include "wifi_board.h"
#include "k10_audio_codec.h"
#include "display/lcd_display.h"
#include "esp_lcd_ili9341.h"
#include "led_control.h"
#include "application.h"
#include "button.h"
#include "config.h"
#include "esp32_camera.h"

#include "led/circular_strip.h"
#include "assets/lang_config.h"

#include <esp_log.h>
#include <esp_lcd_panel_vendor.h>
#include <driver/i2c_master.h>
#include <driver/spi_common.h>
#include <wifi_station.h>

#include "esp_io_expander_tca95xx_16bit.h"

#include "mcp_server.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "scd4x.h"


#define TAG "DF-K10"

class Df_K10Board : public WifiBoard
{
private:
    i2c_master_bus_handle_t i2c_bus_;
    esp_io_expander_handle_t io_expander;
    LcdDisplay *display_;
    button_handle_t btn_a;
    button_handle_t btn_b;
    Esp32Camera *camera_;

    button_driver_t *btn_a_driver_ = nullptr;
    button_driver_t *btn_b_driver_ = nullptr;

    CircularStrip *led_strip_;
    // LvglScreenshot *screenshot_ = nullptr;
    // sdmmc_card_t *sd_card_ = nullptr; // SD卡句柄

    SCD4X *scd4x_ = nullptr;

    static Df_K10Board *instance_;

    void InitializeI2c()
    {
        // Initialize I2C peripheral
        i2c_master_bus_config_t i2c_bus_cfg = {
            .i2c_port = (i2c_port_t)1,
            .sda_io_num = AUDIO_CODEC_I2C_SDA_PIN,
            .scl_io_num = AUDIO_CODEC_I2C_SCL_PIN,
            .clk_source = I2C_CLK_SRC_DEFAULT,
            .glitch_ignore_cnt = 7,
            .intr_priority = 0,
            .trans_queue_depth = 0,
            .flags = {
                .enable_internal_pullup = 1,
            },
        };
        ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_cfg, &i2c_bus_));

        // Initialize SCD4X sensor
        scd4x_ = new SCD4X(i2c_bus_);
        if (scd4x_->begin())
        {
            ESP_LOGI(TAG, "SCD4X sensor initialized successfully");

            // Read and print serial number
            uint16_t serial[3];
            if (scd4x_->getSerialNumber(serial))
            {
                ESP_LOGI(TAG, "SCD4X sensor serial number: %04X-%04X-%04X",
                         serial[0], serial[1], serial[2]);
            }

            // Enable periodic measurement mode
            scd4x_->enablePeriodMeasure(SCD4X_MODE_PERIODIC);
            ESP_LOGI(TAG, "SCD4X periodic measurement mode enabled");

            // Initialize sensor logging system (directory and CSV file)
            // if (scd4x_->InitializeSensorDataLogging())
            // {
            //     ESP_LOGI(TAG, "SCD4X sensor logging system initialized");
            // }
            // else
            // {
            //     ESP_LOGW(TAG, "Failed to initialize SCD4X sensor logging system");
            // }

            // Timed logging functionality is integrated into SCD4X class
            // Directory initialization is handled by sdcard_bsp component as per project specifications
        }
        else
        {
            ESP_LOGE(TAG, "Failed to initialize SCD4X sensor");
            scd4x_ = nullptr;
        }
    }

    void InitializeSpi()
    {
        spi_bus_config_t buscfg = {};
        buscfg.mosi_io_num = GPIO_NUM_21;
        buscfg.miso_io_num = GPIO_NUM_NC;
        buscfg.sclk_io_num = GPIO_NUM_12;
        buscfg.quadwp_io_num = GPIO_NUM_NC;
        buscfg.quadhd_io_num = GPIO_NUM_NC;
        buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
        ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
    }

    // bool InitializeSdcard()
    // {
    //     if (sd_card_ != nullptr)
    //     {
    //         return true; // 已经初始化过
    //     }

    //     // Use sdcard_bsp library for SD card initialization
    //     sdcard_init();

    //     // Get the SD card handle from sdcard_bsp
    //     sd_card_ = sdcard_get_handle();

    //     if (sd_card_ == nullptr)
    //     {
    //         ESP_LOGE(TAG, "Failed to initialize SD card via sdcard_bsp");
    //         return false;
    //     }

    //     // Verify SD card is accessible and writable
    //     const char *mount_point = "/sdcard";
    //     struct stat st;
    //     if (stat(mount_point, &st) != 0)
    //     {
    //         int error_code = errno;
    //         ESP_LOGE(TAG, "SD card mount point not accessible after initialization: %s (errno: %d - %s)",
    //                  mount_point, error_code, strerror(error_code));
    //         return false;
    //     }

    //     if (!S_ISDIR(st.st_mode))
    //     {
    //         ESP_LOGE(TAG, "SD card mount point is not a directory: %s", mount_point);
    //         return false;
    //     }

    //     // Try to fix permissions if not writable
    //     if (access(mount_point, W_OK) != 0)
    //     {
    //         ESP_LOGW(TAG, "SD card mount point not writable, attempting to fix...");
    //         esp_err_t perm_result = sdcard_fix_mount_permissions();
    //         if (perm_result != ESP_OK)
    //         {
    //             ESP_LOGE(TAG, "Failed to fix SD card mount permissions: %s", esp_err_to_name(perm_result));
    //             return false;
    //         }
    //     }

    //     ESP_LOGI(TAG, "SD card initialized successfully via sdcard_bsp");
    //     return true;
    // }

    esp_err_t IoExpanderSetLevel(uint16_t pin_mask, uint8_t level)
    {
        return esp_io_expander_set_level(io_expander, pin_mask, level);
    }

    uint8_t IoExpanderGetLevel(uint16_t pin_mask)
    {
        uint32_t pin_val = 0;
        esp_io_expander_get_level(io_expander, DRV_IO_EXP_INPUT_MASK, &pin_val);
        pin_mask &= DRV_IO_EXP_INPUT_MASK;
        return (uint8_t)((pin_val & pin_mask) ? 1 : 0);
    }

    void InitializeIoExpander()
    {
        esp_io_expander_new_i2c_tca95xx_16bit(
            i2c_bus_, ESP_IO_EXPANDER_I2C_TCA9555_ADDRESS_000, &io_expander);

        esp_err_t ret;
        ret = esp_io_expander_print_state(io_expander);
        if (ret != ESP_OK)
        {
            ESP_LOGE(TAG, "Print state failed: %s", esp_err_to_name(ret));
        }
        ret = esp_io_expander_set_dir(io_expander, IO_EXPANDER_PIN_NUM_0,
                                      IO_EXPANDER_OUTPUT);
        if (ret != ESP_OK)
        {
            ESP_LOGE(TAG, "Set direction failed: %s", esp_err_to_name(ret));
        }
        ret = esp_io_expander_set_level(io_expander, 0, 1);
        if (ret != ESP_OK)
        {
            ESP_LOGE(TAG, "Set level failed: %s", esp_err_to_name(ret));
        }
        ret = esp_io_expander_set_dir(
            io_expander, DRV_IO_EXP_INPUT_MASK,
            IO_EXPANDER_INPUT);
        if (ret != ESP_OK)
        {
            ESP_LOGE(TAG, "Set direction failed: %s", esp_err_to_name(ret));
        }
    }

    void InitializeButtons()
    {
        instance_ = this;
        // screenshot_ = new LvglScreenshot();
        // screenshot_->Init();

        // Button A
        button_config_t btn_a_config = {
            .long_press_time = 1000,
            .short_press_time = 0};
        btn_a_driver_ = (button_driver_t *)calloc(1, sizeof(button_driver_t));
        btn_a_driver_->enable_power_save = false;
        btn_a_driver_->get_key_level = [](button_driver_t *button_driver) -> uint8_t
        {
            return !instance_->IoExpanderGetLevel(IO_EXPANDER_PIN_NUM_2);
        };
        ESP_ERROR_CHECK(iot_button_create(&btn_a_config, btn_a_driver_, &btn_a));
        iot_button_register_cb(btn_a, BUTTON_SINGLE_CLICK, nullptr, [](void *button_handle, void *usr_data)
                               {
            auto self = static_cast<Df_K10Board*>(usr_data);
            auto& app = Application::GetInstance();
            if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
                self->ResetWifiConfiguration();
            }
            app.ToggleChatState(); }, this);
        iot_button_register_cb(btn_a, BUTTON_LONG_PRESS_START, nullptr, [](void *button_handle, void *usr_data)
                               {
            auto self = static_cast<Df_K10Board*>(usr_data);
            auto codec = self->GetAudioCodec();
            auto volume = codec->output_volume() - 10;
            if (volume < 0) {
                volume = 0;
            }
            codec->SetOutputVolume(volume);
            self->GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume)); }, this);

        // Button B
        button_config_t btn_b_config = {
            .long_press_time = 1000,
            .short_press_time = 0};
        btn_b_driver_ = (button_driver_t *)calloc(1, sizeof(button_driver_t));
        btn_b_driver_->enable_power_save = false;
        btn_b_driver_->get_key_level = [](button_driver_t *button_driver) -> uint8_t
        {
            return !instance_->IoExpanderGetLevel(IO_EXPANDER_PIN_NUM_12);
        };
        ESP_ERROR_CHECK(iot_button_create(&btn_b_config, btn_b_driver_, &btn_b));
        iot_button_register_cb(btn_b, BUTTON_SINGLE_CLICK, nullptr, [](void *button_handle, void *usr_data)
                               {
            auto self = static_cast<Df_K10Board*>(usr_data);
            auto& app = Application::GetInstance();
            if (app.GetDeviceState() == kDeviceStateStarting && !WifiStation::GetInstance().IsConnected()) {
                self->ResetWifiConfiguration();
            }
            app.ToggleChatState(); }, this);
        iot_button_register_cb(btn_b, BUTTON_LONG_PRESS_START, nullptr, [](void *button_handle, void *usr_data)
                               {
            auto self = static_cast<Df_K10Board*>(usr_data);
            auto codec = self->GetAudioCodec();
            auto volume = codec->output_volume() + 10;
            if (volume > 100) {
                volume = 100;
            }
            codec->SetOutputVolume(volume);
            self->GetDisplay()->ShowNotification(Lang::Strings::VOLUME + std::to_string(volume)); }, this);
        // iot_button_register_cb(btn_b, BUTTON_SINGLE_CLICK, nullptr, [](void *button_handle, void *usr_data)
        //                        {
        //     auto self = static_cast<Df_K10Board*>(usr_data);
        //     DisplayLockGuard lock(self->GetDisplay());
        //     // lock(3000);
        //     self->screenshot_->TakeJpegScreenshot();            
            // self->GetDisplay()->ShowNotification("Screenshot saved");
        // }, this);

    }

    void InitializeCamera()
    {

        camera_config_t config = {};
        config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择  用于生成XCLK时钟 但是S3不用
        config.ledc_timer = LEDC_TIMER_2;     // LEDC timer选择  用于生成XCLK时钟 但是S3不用
        config.pin_d0 = CAMERA_PIN_D2;
        config.pin_d1 = CAMERA_PIN_D3;
        config.pin_d2 = CAMERA_PIN_D4;
        config.pin_d3 = CAMERA_PIN_D5;
        config.pin_d4 = CAMERA_PIN_D6;
        config.pin_d5 = CAMERA_PIN_D7;
        config.pin_d6 = CAMERA_PIN_D8;
        config.pin_d7 = CAMERA_PIN_D9;
        config.pin_xclk = CAMERA_PIN_XCLK;
        config.pin_pclk = CAMERA_PIN_PCLK;
        config.pin_vsync = CAMERA_PIN_VSYNC;
        config.pin_href = CAMERA_PIN_HREF;
        config.pin_sccb_sda = -1; // 这里如果写-1 表示使用已经初始化的I2C接口
        config.pin_sccb_scl = CAMERA_PIN_SIOC;
        config.sccb_i2c_port = 1; //  这里如果写1 默认使用I2C1
        config.pin_pwdn = CAMERA_PIN_PWDN;
        config.pin_reset = CAMERA_PIN_RESET;
        config.xclk_freq_hz = XCLK_FREQ_HZ;
        config.pixel_format = PIXFORMAT_RGB565;
        config.frame_size = FRAMESIZE_VGA;
        config.jpeg_quality = 12;
        config.fb_count = 1;
        config.fb_location = CAMERA_FB_IN_PSRAM;
        config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;

        camera_ = new Esp32Camera(config);
    }

    void InitializeIli9341Display()
    {
        esp_lcd_panel_io_handle_t panel_io = nullptr;
        esp_lcd_panel_handle_t panel = nullptr;

        // 液晶屏控制IO初始化
        ESP_LOGD(TAG, "Install panel IO");
        esp_lcd_panel_io_spi_config_t io_config = {};
        io_config.cs_gpio_num = GPIO_NUM_14;
        io_config.dc_gpio_num = GPIO_NUM_13;
        io_config.spi_mode = 0;
        io_config.pclk_hz = 40 * 1000 * 1000;
        io_config.trans_queue_depth = 10;
        io_config.lcd_cmd_bits = 8;
        io_config.lcd_param_bits = 8;
        ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(SPI3_HOST, &io_config, &panel_io));

        // 初始化液晶屏驱动芯片
        ESP_LOGD(TAG, "Install LCD driver");
        esp_lcd_panel_dev_config_t panel_config = {};
        panel_config.reset_gpio_num = GPIO_NUM_NC;
        panel_config.bits_per_pixel = 16;
        panel_config.color_space = ESP_LCD_COLOR_SPACE_BGR;

        ESP_ERROR_CHECK(esp_lcd_new_panel_ili9341(panel_io, &panel_config, &panel));
        ESP_ERROR_CHECK(esp_lcd_panel_reset(panel));
        ESP_ERROR_CHECK(esp_lcd_panel_init(panel));
        ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel, DISPLAY_BACKLIGHT_OUTPUT_INVERT));
        ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY));
        ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y));
        ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel, true));

        display_ = new SpiLcdDisplay(panel_io, panel,
                                     DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY);
    }

    // 物联网初始化，添加对 AI 可见设备
    void InitializeIot()
    {
        led_strip_ = new CircularStrip(BUILTIN_LED_GPIO, 3);
        new LedStripControl(led_strip_);

        // 确保 SD 卡已挂载
        // if (sd_card_ == nullptr)
        // {
        //     ESP_LOGW(TAG, "SD card is not mounted yet, trying to initialize...");
        //     if (!InitializeSdcard())
        //     {
        //         ESP_LOGE(TAG, "Failed to initialize SD card");
        //         // 可以选择使用备用存储位置或记录错误
        //         return;
        //     }
        // }

        auto &mcp_server = McpServer::GetInstance();

        // SCD4X传感器数据工具
        mcp_server.AddTool("self.sensor.scd4x_data",
                           "获取SCD4X传感器的CO2浓度、温度和湿度数据。\n"
                           "参数：无\n"
                           "返回：包含CO2(ppm)、温度(°C)和湿度(%)的JSON格式数据。",
                           PropertyList(),
                           [this](const PropertyList &properties) -> ReturnValue
                           {
                               if (!this->scd4x_)
                               {
                                   return "{\"success\": false, \"message\": \"SCD4X传感器未初始化\"}";
                               }

                               if (!this->scd4x_->getDataReadyStatus())
                               {
                                   return "{\"success\": false, \"message\": \"传感器数据未就绪\"}";
                               }

                               SCD4X::Measurement data;
                               this->scd4x_->readMeasurement(&data);

                               char result[256];
                               snprintf(result, sizeof(result),
                                        "{\"success\": true, "
                                        "\"co2_ppm\": %d, "
                                        "\"temperature\": %.1f, "
                                        "\"humidity\": %.1f}",
                                        data.co2_ppm, data.temperature, data.humidity);
                               return result;
                           });

      #if 0
                           // 启动SCD4X传感器定时数据记录工具

        mcp_server.AddTool("self.sensor.start_timed_scd4x_logging",
                           "启动SCD4X传感器定时数据记录功能。按指定间隔自动采集并保存传感器数据到SD卡。\n"
                           "参数:\n"
                           "  `interval_seconds`: 数据采集间隔时间（秒），范围10-3600秒（1小时）。\n"
                           "返回:\n"
                           "  定时数据记录启动状态的JSON格式信息。",
                           PropertyList({Property("interval_seconds", kPropertyTypeInteger, 10, 3600)}),
                           [this](const PropertyList &properties) -> ReturnValue
                           {
                               // 检查是否已经在运行
                               // if (this->timed_scd4x_->IsLogging())  // Updated to use SCD4X method
                               if (this->scd4x_->IsTimedLogging())
                               {
                                   return "{\"success\": false, \"message\": \"SCD4X数据记录已在运行中，请先停止当前任务\"}";
                               }

                               auto interval = properties["interval_seconds"].value<int>();

                               // 验证参数
                               if (interval < 10 || interval > 3600)
                               {
                                   return "{\"success\": false, \"message\": \"数据采集间隔必须在10-3600秒之间\"}";
                               }

                               // 启动定时数据记录
                               // if (this->timed_scd4x_->StartTimedLogging(interval))  // Updated to use SCD4X method
                               if (this->scd4x_->StartTimedLogging(interval))
                               {
                                   char result[256];
                                   snprintf(result, sizeof(result),
                                            "{\"success\": true, \"message\": \"SCD4X数据记录已启动\", \"interval_seconds\": %d, \"log_path\": \"%s\"}",
                                            interval, "/sdcard/sensor_data/scd4x");
                                   return result;
                               }
                               else
                               {
                                   return "{\"success\": false, \"message\": \"SCD4X数据记录启动失败，请检查SD卡状态\"}";
                               }
                           });

        // 停止SCD4X传感器定时数据记录工具
        mcp_server.AddTool("self.sensor.stop_timed_scd4x_logging",
                           "停止当前正在运行的SCD4X传感器定时数据记录功能。\n"
                           "参数：无\n"
                           "返回:\n"
                           "  停止操作的状态信息。",
                           PropertyList(), // 无参数
                           [this](const PropertyList &properties) -> ReturnValue
                           {
                               // 检查是否正在运行
                               // if (!this->timed_scd4x_->IsLogging())  // Updated to use SCD4X method
                               if (!this->scd4x_->IsTimedLogging())
                               {
                                   return "{\"success\": false, \"message\": \"SCD4X数据记录当前未运行\"}";
                               }

                               // 停止定时数据记录
                               // this->timed_scd4x_->StopTimedLogging();  // Updated to use SCD4X method
                               this->scd4x_->StopTimedLogging();
                               return "{\"success\": true, \"message\": \"SCD4X数据记录已停止\"}";
                           });

        // 立即保存SCD4X传感器数据工具
        mcp_server.AddTool("self.sensor.save_scd4x_data",
                           "立即采集并保存一次SCD4X传感器数据到SD卡。\n"
                           "参数：无\n"
                           "返回:\n"
                           "  数据保存状态的JSON格式信息。",
                           PropertyList(), // 无参数
                           [this](const PropertyList &properties) -> ReturnValue
                           {
                               // if (this->timed_scd4x_->SaveCurrentData())  // Updated to use SCD4X method
                               if (this->scd4x_->SaveCurrentData())
                               {

                                   return "{\"success\": true, \"message\": \"SCD4X数据已保存\"}";
                               }
                               else
                               {
                                   return "{\"success\": false, \"message\": \"SCD4X数据保存失败，请检查传感器和SD卡状态\"}";
                               }
                           });
    #endif
    }

public:
    Df_K10Board()
    {
        InitializeI2c();
        InitializeIoExpander();
        InitializeSpi();
        // InitializeSdcard();
        InitializeIli9341Display();
        InitializeButtons();
        InitializeIot();
        InitializeCamera();
    }

    virtual Led *GetLed() override
    {
        return led_strip_;
    }

    virtual AudioCodec *GetAudioCodec() override
    {
        static K10AudioCodec audio_codec(
            i2c_bus_,
            AUDIO_INPUT_SAMPLE_RATE,
            AUDIO_OUTPUT_SAMPLE_RATE,
            AUDIO_I2S_GPIO_MCLK,
            AUDIO_I2S_GPIO_BCLK,
            AUDIO_I2S_GPIO_WS,
            AUDIO_I2S_GPIO_DOUT,
            AUDIO_I2S_GPIO_DIN,
            AUDIO_CODEC_PA_PIN,
            AUDIO_CODEC_ES8311_ADDR,
            AUDIO_CODEC_ES7210_ADDR,
            AUDIO_INPUT_REFERENCE);
        return &audio_codec;
    }

    virtual Camera *GetCamera() override
    {
        return camera_;
    }

    virtual Display *GetDisplay() override
    {
        return display_;
    }
};

DECLARE_BOARD(Df_K10Board);

Df_K10Board *Df_K10Board::instance_ = nullptr;
